/*                          UX-Framework                               
 *                                                                 
 *  iZE Co.,Ltd. Copyright 2009 All rights reserved.          
 *  This file is distributed under the terms of the GNU Lesser 
 *  General Public License, described in file LICENSE.                                     
 */

package jp.ize.ux.components;

// {{{ imports
import jp.ize.iwp.RuntimeEngine;
import jp.ize.ux.UXRoot;
import jp.ize.ux.UXObject;
import jp.ize.ux.UXController;
import jp.ize.ux.UXInteraction;
import jp.ize.ux.UXFocusManager;
import jp.ize.ux.components.UXButton;
import jp.ize.ux.components.themes.basic.UXWindowResource;
import jp.ize.ux.interactions.UXGeneralInteraction;
import jp.ize.ux.states.UXBasicState;
import jp.ize.ux.events.UXMouseEvent;
import jp.ize.ux.acts.Act;
import jp.ize.ux.geom.UXPoint;
import jp.ize.ux.geom.UXSize;
import flash.text.TextFieldAutoSize;
// }}}
// {{{ class UXWindowAct extends Act
/**
 * UXWindowAct クラス<br>
 * UXWindowのデフォルトアクションです。
 */
class UXWindowAct extends Act
{
	// {{{ public function new()
	/**
	 * コンストラクタです。<br>
	 */
	public function new()
	{
		super();
	}
	// }}}
	// {{{ public function focus() : UXWindowState -> Void
	/**
	 * フォーカスされた時のデフォルトアクションです。
	 */
	public function focus() : UXWindowState -> Void
	{
		return function( s : UXWindowState ) {
		}
	}
	// }}}
	// {{{ public function unfocus() : UXWindowState -> Void
	/**
	 * フォーカスが解除された時のデフォルトアクションです。
	 */
	public function unfocus() : UXWindowState -> Void
	{
		return function( s : UXWindowState ) {
		}
	}
	// }}}
	// {{{ public function resize() : UXWindowState -> Void
	/**
	 * ウィンドウの大きさが変化した時のデフォルトアクションです。
	 */
	public function resize() : UXWindowState -> Void
	{
		return function( s : UXWindowState ) {
		}
	}
	// }}}
	// {{{ public function show() : UXWindowState -> Void
	/**
	 * 表示された時のデフォルトアクションです。
	 */
	public function show() : UXWindowState -> Void
	{
		return function( s : UXWindowState ) {
			s.target.visible = true;
		}
	}
	// }}}
	// {{{ public function hide() : UXWindowState -> Void
	/**
	 * 非表示になった時のデフォルトアクションdす。
	 */
	public function hide() : UXWindowState -> Void
	{
		return function( s : UXWindowState ) {
			s.target.visible = false;
		}
	}
	// }}}
}
// }}}
// {{{ class UXWindowState extends UXBasicState
/**
 * UXWindowState クラス<br>
 * UXWindowの現在の状態を表すオブジェクトです。
 */
class UXWindowState extends UXBasicState
{
	// {{{ properties
	// {{{ public var pos( default, default ) : UXPoint;
	/**
	* 現在のポインタの場所をリサイズ用に保存します。
	*/
	public var pos( default, default ) : UXPoint;
	// }}}
	// {{{ public var resizing( default, default ) : Bool;
	/**
	* 現在リサイズ中であるかどうかのフラグです。
	*/
	public var resizing( default, default ) : Bool;
	// }}}
	// {{{ public var resources( default, default ) : UXWindowResource;
	/**
	* 描画に使用するリソースです。
	*/
	public var resources( default, default ) : UXWindowResource;
	// }}}
	// {{{ public var panel(default, default) : UXScrollArea
	/**
	* 背景となるコンポーネント。
	*/
	public var panel(default, default) : UXScrollArea;
	// }}}
	// {{{ public var title( default, default ) : UXLabel;
	/**
	* 上部のタイトルバーに表示させる文字列を設定します。
	*/
	public var title( default, default ) : UXLabel;
	// }}}
	// {{{ public var icon( default, default ) : UXImage;
	/**
	* タイトルバーに表示させるアイコン画像を設定します。デフォルトではnullです。
	*/
	public var icon( default, default ) : UXImage;
	// }}}
	// {{{ public var titleBar(default, default) : UXComponentResource
	/**
	* タイトルバーコンポーネントです。
	*/
	public var titleBar(default, default) : UXComponentResource;
	// }}}
	// {{{ public var closeButton( default, setCloseButton ) : Bool;
	/**
	* ウィンドウの右上にバツボタンを表示するかどうかを設定します。
	*/
	public var closeButton( default, setCloseButton ) : Bool;
	// }}}
	// {{{ public var resizable( default, setResizable ) : Bool;
	/**
	* リサイズ可能かどうかを設定します。
	*/
	public var resizable( default, setResizable ) : Bool;
	// }}}
	// {{{ public var modal( default, setModal ) : Bool;
	/**
	* モーダルなウィンドウにするかどうかを設定します。
	*/
	public var modal( default, setModal ) : Bool;
	// }}}
	// {{{ public var acts(default, null) : UXWindowAct
	/**
	* デフォルトの動きです。
	*/
	public var acts(default, null) : UXWindowAct;
	// }}}
	// {{{ public var cornerRadius( default, default ) : Float;
	/**
	 * ウィンドウの角の丸みの半径です。デフォルト値は 10 です。
	 */
	public var cornerRadius( default, default ) : Float;
	// }}}
	// {{{ public var headerHeight( default, default ) : Float;
	/**
	 * ヘッダの高さを表します。デフォルト値は 30 です。
	 */
	public var headerHeight( default, default ) : Float;
	// }}}
	// {{{ public var margin( default, default ) : Float;
	/**
	 * マージンの量を表します。デフォルト値は 5 です。
	 */
	public var margin( default, default ) : Float;
	// }}}
	// {{{ public var shadow_margin( default, default ) : Float;
	/**
	 * 影の部分のピクセル数を表します。デフォルト値は 5 です。
	 */
	public var shadow_margin( default, default ) : Float;
	// }}}
	// {{{ public var focusManager(default, default) : UXFocusManager
	/**
	 * このコンポーネントが属するフォーカスグループの管理オブジェクトです。
	 * このコンポーネントがフォーカスを受け取らない場合はnullです。
	 */
	public var focusManager(default, default) : UXFocusManager;
	// }}}
	// {{{ public var size(default, default) : UXSize
	/**
	 * Window内の幅・高さです。
	 */
	public var size(default, default) : UXSize;
	// }}}
	// }}}
	// {{{ public function new( size:UXSize )
	/**
	* コンストラクタ
	*/
	public function new( size:UXSize )
	{
		super();
		focusManager = new UXFocusManager();
		resizing = false;
		cornerRadius = 10;
		headerHeight = 30;
		modal = false;
		margin = 5;
		shadow_margin = 5;
		resizable = true;
		closeButton = true;
		acts = new UXWindowAct();
		this.size = size;
		var d = (20+margin)*2 + shadow_margin;
		panel = new UXScrollArea( new UXSize(size.width-d,size.height-d-headerHeight) );
		resources = new UXWindowResource( this );
		resources.titleBar.addUXEventListener( UXMouseEvent.DOWN, onTitleBarMouseDown );
		resources.titleBar.addUXEventListener( UXMouseEvent.UP,   onTitleBarMouseUp );
		resources.titleBar.addUXEventListener( UXMouseEvent.OVER, onTitleBarMouseUp );
		resources.titleBar.addUXEventListener( UXMouseEvent.OUT,  onTitleBarMouseUp );
		resources.closeButton.addUXEventListener( UXMouseEvent.CLICK, onCloseButtonClick );
		resources.closeButton.addUXEventListener( UXMouseEvent.DOWN,  onCloseButtonMouseDown );
		resources.closeButton.addUXEventListener( UXMouseEvent.UP,    onCloseButtonMouseUp );
		resources.closeButton.addUXEventListener( UXMouseEvent.OVER,  onCloseButtonMouseOver );
		resources.closeButton.addUXEventListener( UXMouseEvent.OUT,   onCloseButtonMouseOut );
		resources.frame.addUXEventListener( UXMouseEvent.DOWN, onFrameMouseDown );
		resources.frame.addUXEventListener( UXMouseEvent.MOVE, onFrameMouseMove );
		resources.frame.addUXEventListener( UXMouseEvent.UP,   onFrameMouseUp );
		resources.frame.addUXEventListener( UXMouseEvent.OVER, onFrameMouseOver );
		resources.frame.addUXEventListener( UXMouseEvent.OUT,  onFrameMouseOut );
	}
	// }}}
	// {{{ public function setModal( b:Bool ) : Bool

	public function setModal( b:Bool ) : Bool
	{
		if ( target!=null ) {
			var win = cast(target,UXWindow);
			var g = win.graphics;
			if ( b ) {
				g.clear();
				g.beginFill( 0xFFFFFF, 0.5 );
				g.drawRect( -UXRoot.getWidth(), -UXRoot.getHeight(),
								UXRoot.getWidth()*2, UXRoot.getHeight()*2);
				g.endFill();
			} else {
				g.clear();
			}
		}
		modal = b;
		return modal;
	}

	// }}}
	// {{{ public function setCloseButton( b:Bool ) : Bool

	public function setCloseButton( b:Bool ) : Bool
	{
		if ( target!=null ) {
			if ( resources!=null && resources.closeButton!=null ) {
				resources.closeButton.visible = b;
			}
		}
		closeButton = b;
		return closeButton;
	}

	// }}}
	// {{{ public function setResizable( b:Bool ) : Bool

	public function setResizable( b:Bool ) : Bool
	{
		if ( target!=null ) {
			if ( resources!=null && resources.frame!=null ) {
				resources.frame.visible = b;
			}
		}
		resizable = b;
		return resizable;
	}

	// }}}
	// {{{ public function onTitleBarMouseDown( e:Dynamic ) : Void

	public function onTitleBarMouseDown( e:Dynamic ) : Void
	{
		target.startDrag(false);
	}

	// }}}
	// {{{ public function onTitleBarMouseUp( e:Dynamic ) : Void

	public function onTitleBarMouseUp( e:Dynamic ) : Void
	{
		target.stopDrag();
	}

	// }}}
	// {{{ public function onCloseButtonClick( e:Dynamic ) : Void

	public function onCloseButtonClick( e:Dynamic ) : Void
	{
		trace("click");
		cast(target,UXWindow).ctrl.trigger("Close");
	}

	// }}}
	// {{{ public function onCloseButtonMouseDown( e:Dynamic ) : Void

	public function onCloseButtonMouseDown( e:Dynamic ) : Void
	{
		resources.closeButton.pressed();
	}

	// }}}
	// {{{ public function onCloseButtonMouseUp( e:Dynamic ) : Void

	public function onCloseButtonMouseUp( e:Dynamic ) : Void
	{
		resources.closeButton.highlighted();
	}

	// }}}
	// {{{ public function onCloseButtonMouseOver( e:Dynamic ) : Void

	public function onCloseButtonMouseOver( e:Dynamic ) : Void
	{
		resources.closeButton.highlighted();
	}

	// }}}
	// {{{ public function onCloseButtonMouseOut( e:Dynamic ) : Void

	public function onCloseButtonMouseOut( e:Dynamic ) : Void
	{
		resources.closeButton.normal();
	}

	// }}}
	// {{{ public function onFrameMouseDown( e:Dynamic ) : Void

	public function onFrameMouseDown( e:Dynamic ) : Void
	{
		pos = new UXPoint( e.stageX, e.stageY );
		resizing = true;
		resources.frame.startDrag(false);
	}

	// }}}
	// {{{ public function onFrameMouseMove( e:Dynamic ) : Void

	public function onFrameMouseMove( e:Dynamic ) : Void
	{
		if ( resizing ) {
			var dw = e.stageX - pos.x;
			var dh = e.stageY - pos.y;
			var p1 = new flash.geom.Point( e.stageX, e.stageY );
			var p2 = resources.frame.globalToLocal(p1);
			if ( p2.x < 20 ) {
				dw = -dw;
				target.startDrag(false);
			}
			if ( p2.y < 20 ) {
				dh = -dh;
				target.startDrag(false);
			}
			size.width  += dw;
			size.height += dh;
			if ( size.width < headerHeight*2 ) {
				size.width  = headerHeight*2;
			}
			if ( size.height < headerHeight*2 ) {
				size.height  = headerHeight*2;
			}
			pos = new UXPoint( e.stageX, e.stageY );
			refresh();
		}
	}

	// }}}
	// {{{ public function onFrameMouseUp( e:Dynamic ) : Void

	public function onFrameMouseUp( e:Dynamic ) : Void
	{
		refreshAll();
	}

	// }}}
	// {{{ public function onFrameMouseOver( e:Dynamic ) : Void

	public function onFrameMouseOver( e:Dynamic ) : Void
	{
		#if flash10
		flash.ui.Mouse.cursor = flash.ui.MouseCursor.HAND;
		#end
	}

	// }}}
	// {{{ public function onFrameMouseOut( e:Dynamic ) : Void

	public function onFrameMouseOut( e:Dynamic ) : Void
	{
		refreshAll();
		#if flash10
		flash.ui.Mouse.cursor = flash.ui.MouseCursor.AUTO;
		#end
	}

	// }}}
	// {{{ public function refresh() : Void

	public function refresh() : Void
	{
		var d = (20+margin)*2 + shadow_margin;
		resources.titleBar.normal();
		resources.closeButton.normal();
		resources.background.normal();
		panel.setSize( new UXSize(size.width-d,size.height-d-headerHeight) );
		panel.x = 20 + margin;
		panel.y = 20 + margin + headerHeight;
		title.label.width = size.width - headerHeight*1.5;
	}

	// }}}
	// {{{ public function refreshAll() : Void

	public function refreshAll() : Void
	{
		target.stopDrag();
		resources.frame.stopDrag();
		resizing = false;
		resources.frame.normal();
		resources.titleBar.normal();
		resources.closeButton.normal();
		resources.background.normal();
		resources.frame.x = 0;
		resources.frame.y = 0;
	}

	// }}}
}
// }}}

// {{{ class UXWindow extends UXComponent<UXWindowState>
/**
 * UXWindowクラス<br>
 * 
 *
 * @author		iZE Co., Ltd.<br>
 * @version		$Id$<br>
 */
class UXWindow extends UXComponent<UXWindowState>
{
	// {{{ public function new( size:UXSize, ?title:String )
	/**
	 * コンストラクタです。
	 *
	 * @param size: ウィンドウのサイズを指定します。
	 * @param title: ウィンドウのタイトルを指定します。省略可能です。
	 *
	 * ウィンドウのサイズには、デフォルトでは、タイトルバーの高さ 30、
	 * スクロールバーの垂直用の幅 20、水平用の高さ 20 を含みます。
	 */
	public function new( size:UXSize, ?title:String )
	{
		state = new UXWindowState( size );
		state.target = this;
		ctrl = new UXController<UXWindowState>( state );
		super(ctrl);
		if ( title==null ) title = "";
		state.title = new UXLabel( title, 16, 0x666666 );
		super.addUXChild( state.resources.background );
		super.addUXChild( state.panel );
		super.addUXChild( state.resources.titleBar );
		super.addUXChild( state.resources.closeButton );
		super.addUXChild( state.resources.frame );
		state.resources.titleBar.addUXChild( state.title );
		state.title.label.autoSize = TextFieldAutoSize.NONE;
		state.title.label.width = state.resources.titleBar.width;
		state.title.x = 5;
		state.title.y = 5;
		state.panel.x = 20 + state.margin;
		state.panel.y = 20 + state.margin + state.headerHeight;

		ctrl.addInteraction( new UXWindowCloseInteraction() );

		var me = this;
		ctrl.getInteraction("Close").addAct( state.acts.hide() );
		ctrl.getInteraction("Focus").addReactEvent( UXMouseEvent.DOWN );
		ctrl.getInteraction("Focus").addAct( function(s){ me.top(); } );
	}
	// }}}
	// {{{ private function attachResource() : Void
	/**
	 * ボタンに対するグローバルなリソースをresourceプロパティに取得する関数です。
	 */
	private function attachResource() : Void
	{
	}
	// }}}
	// {{{ public function update( updator : UXWindowState -> Void ) : Void
	/**
	 * このコンポーネントの状態を直接変更するメソッドです。状態のどんな操作も可能になるので、
	 * このメソッドの使用には注意が必要です。
	 */
	public function update( updator : UXWindowState -> Void ) : Void
	{
		updator( state );
	}
	// }}}
	// {{{ public function addUXChild( child : UXObject ) : Void
	/**
	 * 子要素を加えます。
	 */
	public override function addUXChild( child : UXObject ) : Void
	{
		state.panel.addUXChild( child );
	}
	// }}}
	// {{{ public function removeUXChild( child : UXObject ) : Void
	/**
	 * 指定された子要素をコンテナから削除します。
	 */
	public override function removeUXChild( child : UXObject ) : Void
	{
		state.panel.removeUXChild( child );
	}
	// }}}
	// {{{ public function top() : Void
	/**
	 * 前面にもってきます。
	 */
	public function top() : Void
	{
		var c = parent.getChildAt(parent.numChildren-1);
		parent.swapChildren( c, this );
	}
	// }}}
	// {{{ public function bottom() : Void
	/**
	 * 背面にもってきます。
	 */
	public function bottom() : Void
	{
		var c = parent.getChildAt(0);
		parent.swapChildren( c, this );
	}
	// }}}
}
// }}}

// {{{ class UXWindowCloseInteraction extends UXGeneralInteraction<UXWindowState>
/**
 * UXWindowCloseInteraction クラス<br>
 * ウィンドウを閉じる事に対するデフォルトインタラクションです。
 */
class UXWindowCloseInteraction extends UXGeneralInteraction<UXWindowState>
{
	// {{{ public function new() : Void
	/**
	* コンストラクタ
	*/
	public function new() : Void
	{
		super("Close");
	}

	// }}}
}
// }}}
